package funcionamento;

/**
 * @author Gean 
 * 121151418
 * @author Eduardo
 *  121151427
 */
public class Processador {

    private int tempoDeProcessamento = 6;                         // atributo que define o tempo de processamento do processador, que sera utilizado para executar os processos 
    private Processo armazena;                                        // variavel auxiliar para armazenar processos...

    
    /* Resumo da funçao :
     * O método abaixo percorre a fila de espera e primeiramente
     * verifica se existem processos na mesma, se existem verifi
     * ca se a algum processo de usuario, entao caso haja,coloca
     * esses processos numa estrutura auxiliar(pilha), logo apos 
     * fazer isso, percorre a fila para verificar se existem proces
     * sos de sistema, se existem,organiza a fila de espera, fazendo 
     * a "andar" para que nao fique espaços vazios (nulos) nela
     * e chama a funçao "execucao" que executa os processos...
     * Quando todos os processos de sistema já tiverem saido da fila
     * de espera, a estrutura auxiliar(pilha) é esvaziada e seus proces
     * sos recolocados na fila para serem executados.
     */
    public void percorrerFila(Fila filaDeEspera, Pilha psistema) {                
        int cont=0;                                                 // variavel auxiliar para contagem
        for (int i = 0; i < filaDeEspera.getData().length; i++) {     // laço for que percorre a fila e verifica se existem processos nela
             if (filaDeEspera.getData()[i] != null){ 
               cont++;           
              }
           }
        if(cont!=0){
       // existindo processos na fila, segue o codigo abaixo...
            
            int cont2=0;                                                                                             // variavel auxiliar para contagem
               for (int i = 0; i < filaDeEspera.getData().length; i++) {                                                  // laço for que percorre a fila e verifica se existem processos de usuario 
                 if (filaDeEspera.getData()[i] != null && filaDeEspera.getData()[i].getTipoDeProcesso().equalsIgnoreCase("usuario")) {
                     cont2++;           
                   }
                }     
              if(cont2 != 0){
             // existindo processos de usuario segue o codigo abaixo...
            
                  for (int j = 0; j < filaDeEspera.getData().length; j++) {
                   if (filaDeEspera.getData()[j] != null && filaDeEspera.getData()[j].getTipoDeProcesso().equalsIgnoreCase("usuario")) {    // laço for que percorre a fila afim de encontrar processos de usuario e se existir passalos a uma estrutura auxiliar(pilha)
                        psistema.Push(filaDeEspera.dequeue(j));                                                                                // usa o metodo dequeue sobreescrito para retirar processos especificos da fila de espera e colocalos na pilha
                        System.out.println("Foi adicionado um processo na pilha");
                       }
                   }
                   
                   System.out.println("\n**********FilaDeEspera************");
                   print(filaDeEspera);
                   
                      int cont3=0;                                                                                     // variavel auxiliar para contagem
                      for (int i = 0; i < filaDeEspera.getData().length; i++) {                                                // laço for que percorre a fila e verifica se existem processos de sistema 
                         if (filaDeEspera.getData()[i] != null && filaDeEspera.getData()[i].getTipoDeProcesso().equalsIgnoreCase("sistema")) {
                             cont3++;           
                           }
                        }
                  if(cont3 != 0){
                 // existindo processos de sistema segue o codigo abaixo...
                      
                     for (int k = 0; k < filaDeEspera.getData().length; k++) {                                     // laço for que percorre a fila de espera afim de organizala, fazela "andar", e evitar que espaços vazios(nulos) fiquem presentes nela
                        if (filaDeEspera.getData()[k] == null && k != filaDeEspera.getData().length-1) {
                           for (int l = k+1; l < filaDeEspera.getData().length; l++) {
                               if(filaDeEspera.getData()[l] != null){
                                  filaDeEspera.getData()[k] = filaDeEspera.getData()[l];
                                  filaDeEspera.getData()[l] = null;
                                  break;                                                                             // para o primeiro o segundo laço for de cima para baixo... (aninhado)
                                }
                             }
                          }
                      }
                
                 for (int x = 0; x < filaDeEspera.getData().length; x++) {                                     // laço for que percorre a fila de espera e colocala de forma coerente aos principios de fila, ou seja, definir corretamente seu inicio e fim
                    if(filaDeEspera.getData()[x] == null){
                       filaDeEspera.setFim(x);
                       break;                                                                                     // para o laço for, já que nao é mais necessario percorrer a fila...
                     }
                   }
                 
                execucao(filaDeEspera);                                                                              // chama o método execucao, que por sua vez simula a exeucao dos processos no processador
                
                for (int i = 0; i < psistema.getVetor().length; i++) {                                                   // laço for que percorre a pilha e lhe esvazia, já colocando os processos na fila
                    while(psistema.getTopo() != 0){
                            filaDeEspera.enqueue(psistema.Pop());    
                          }         
                  }
                System.out.println("\n**********FilaDeEspera************");
                print(filaDeEspera);
                execucao(filaDeEspera);                                                           // já que os processos de sistema já foram executados e a fila esta preenchida por processos de usuario, o metodo é chamado novamente
                 
                }else{                                                                             // nao existindo processos de sistema na fila, segue o codigo abaixo
                    System.out.println("A fila de espera está livre!");                       
                      for (int i = 0; i < psistema.getVetor().length; i++) {                            // retira os processos de usuario da estrutura auxiliar(pilha) e lhes recoloca na fila para posteriormente serem executados
                         while(psistema.getVetor()[psistema.getTopo()] != null){
                            filaDeEspera.enqueue(psistema.Pop());    
                          }         
                        }
                      System.out.println("\n**********FilaDeEspera************");
                      print(filaDeEspera);
                      execucao(filaDeEspera);                                                                // chama o metodo para executar os processos de usuario, agora presentes na fila
                  }  
                
               }else{                                                                                           // se nao existem processos de usuario na fila de espera seque o codigo abaixo
                  System.out.println("Existem somente processos de sistema na fila de espera!");
                  execucao(filaDeEspera);
              }
          
           } else{                                                                                                // se nao existem processos na fila de espera segue o codigo abaixo...
             System.out.println("Não existem processos na fila!");
          }
       }
  
    /* O método abaixo tem por finalidade simular a execução de
     * processos que ocorre em um processador, ele testa se a fila
     * esta vazia, se não estiver, executa os processos existentes nela
     * até a mesma estar totalmente vazia...
     * Na execucao, pega sempre o primeiro elemento da fila e compara seu tempo
     * de execucao(TE) com o tempo de processamento(TP), se TE for maior que TP 
     * o calculo é feito e como o TE do processos nao foi finalizado(zerado) retira
     * o processo do inicio da fila, e lhe coloca no final... Caso o primeiro processo 
     * da fila tiver TE menor ou igual a TP, ele é executado totalmente e é apenas
     * retirado da fila de espera. Esses procedimentos sao repetidos até que a fila 
     * esteja totalmente vazia.
     */
    public void execucao(Fila fila) {                                               
        while(fila.getQtdPosLivre() != fila.getData().length){                   // laço while que faz a execucao ser feita até que "getQtdPosLivre" seja igual ao tamanho da fila, ou seja, que a fila esteja vazia, sem nenhum processo a ser executado
           armazena = fila.getData()[fila.getInicio()];                             // uso da variavel auxiliar, para armazenar um processo
            if (armazena.getTempoDeExecucao() > getTempoDeProcessamento()) {           // compara se o tempo de execucao é maior que o tempo de processamento, se for verdadeiro segue o codigo abaixo...
                    armazena.setTempoDeExecucao(armazena.getTempoDeExecucao() - getTempoDeProcessamento());
                    System.out.println("\nte > tp");
                    
                    fila.dequeue();                                                    // apos o calculo, da um dequeue no processo já que o mesmo nao foi finalizado
                    fila.enqueue(armazena);                                              // manda o "armazena" que é o mesmo processo que nao foi finalizado, para o final da fila. Obs: o armazena foi usado para essa finalidade, preservar o estado do processo...
                    
                    armazena = null;                                                  
                    System.out.println("O processo não foi totalmente finalizado e voltou para o fim da fila...");
                    System.out.println("\n**********FilaDeEspera************");
                    print(fila);
            } else {                                                                         // caso o tempo de execucao do processo nao for maior que o tempo de processamento, segue o codigo abaixo...
                    armazena = fila.getData()[fila.getInicio()];
                    System.out.println("\nte <= tp");
                    fila.dequeue();
                   
                    armazena.setTempoDeExecucao(armazena.getTempoDeExecucao() - getTempoDeProcessamento());
                    armazena = null;
                    System.out.println("O processo foi totalmente finalizado...");
                    System.out.println("\n**********FilaDeEspera************");
                    print(fila); 
               }
           }
       }
    
    /* Método usado para imprimir a fila 
     * e seus processos
     */
    public void print(Fila fila){
        for (int i = 0; i < fila.getData().length; i++) {
           if(fila.getData()[i] != null){
             System.out.println("ID processo: "+fila.getData()[i].getId());    
            }else{
               System.out.println(""+fila.getData()[i]);
                 }
         }
      }
    
    /* Métodos gets e sets para que seja possivel
     * acessar os atributos privados abaixo em
     * outras classes
     */
    public int getTempoDeProcessamento() {
        return tempoDeProcessamento;
    }

    public void setTempoDeProcessamento(int tempoDeProcessamento) {
        this.tempoDeProcessamento = tempoDeProcessamento;
    }
}